﻿/*
* Description: 取CPU使用率和频率数据
*/
#include "sys_cpu_calc.h"
#include <iostream>
#include <algorithm>
#include <winternl.h>
#include <basetsd.h>
#include "log.h"
#include "Psapi.h"
#include "text_util/string_proc.h"
#include <tlhelp32.h>
#include <unordered_set>
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

using namespace std;

namespace {
const int32_t MAX_NUMBER_OF_PROCESSORS = 128;
const int32_t DATA_CONVERSION_SIZE = 1024;
const double INIT_VALUE = 0.0f;
const double TIME_SLICE = 10 * 1000 * 1000;
const uint32_t MAX_PROCESS_SIZE = 10000;
const float MIN_CPU_USAGE = 0.0001f;
const ULONG64 MINI_IO_TOTAL = 6 * 50 * 1024;  // io阈值50kb/s
const int32_t TO_PERCENTAGE = 100;
}

SysCpuCalc &SysCpuCalc::GetInstance()
{
    static SysCpuCalc instance;
    return instance;
}

SysCpuCalc::SysCpuCalc() {}

SysCpuCalc::~SysCpuCalc()
{
    if (phCpuInformation != nullptr) {
        free(phCpuInformation);
        phCpuInformation = nullptr;
    }
    if (dttPhCpuInformation != nullptr) {
        free(dttPhCpuInformation);
        dttPhCpuInformation = nullptr;
    }
    {
        std::unique_lock<std::mutex> lock(mapMtx);
        filterMapProcessInfo.clear();
        mapProcessInfo.clear();
    }
    {
        std::unique_lock<std::mutex> lock(dttMapMtx);
        mapDttProcessInfo.clear();
    }
}

bool SysCpuCalc::AquireToken(HANDLE processHandle, LPCTSTR privilegeName)
{
    if (processHandle == nullptr) {
        return false;
    }
    HANDLE tokenHandle = nullptr;
    TOKEN_PRIVILEGES newToken = { 0 };
    LUID luidDebugLUID;
    if (!OpenProcessToken(processHandle, TOKEN_ADJUST_PRIVILEGES, &tokenHandle)) {
        return false;
    }
    if (!LookupPrivilegeValue(NULL, privilegeName, &luidDebugLUID)) {
        CloseHandle(tokenHandle);
        return false;
    }
    // 进程的权限数量
    newToken.PrivilegeCount = 1;
    newToken.Privileges[0].Luid = luidDebugLUID;
    newToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(tokenHandle, FALSE, &newToken, sizeof(newToken), NULL, NULL)) {
        CloseHandle(tokenHandle);
        return false;
    }
    CloseHandle(tokenHandle);
    return true;
}

bool SysCpuCalc::Init()
{
    if (inited) {
        return true;
    }
    // 当前进程伪句柄
    HANDLE currentProcess = GetCurrentProcess();
    if (currentProcess == nullptr) {
        return false;
    }
    if (!AquireToken(currentProcess, SE_DEBUG_NAME)) {
        return false;
    }
    NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SYSTEM_BASIC_INFORMATION_PERF),
        &phSystemBasicInformation, sizeof(PerfSystemBasicInformation), NULL);
    if (!NtSuccess(status)) {
        return false;
    }
    if (static_cast<int>(phSystemBasicInformation.numberOfProcessors <= 0) ||
        static_cast<int>(phSystemBasicInformation.numberOfProcessors > MAX_NUMBER_OF_PROCESSORS)) {
        LOG_ERR("Apply for memory failed. mapSize={}", phSystemBasicInformation.numberOfProcessors);
        return false;
    }
    numberOfProcessors = phSystemBasicInformation.numberOfProcessors;
    phCpuInformation = reinterpret_cast<PerfSystemProcessorInfo *>(
        malloc(sizeof(PerfSystemProcessorInfo) * static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors)));
    if (phCpuInformation == nullptr) {
        return false;
    }
    dttPhCpuInformation = reinterpret_cast<PerfSystemProcessorInfo *>(
        malloc(sizeof(PerfSystemProcessorInfo) * static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors)));
    if (dttPhCpuInformation == nullptr) {
        return false;
    }
    CollectProcLoad();
    CollectProcCpuLoad();
    inited = true;
    return true;
}

void SysCpuCalc::PhpUpdateCpuInformation()
{
    if (phCpuInformation == nullptr) {
        sysCpuUsage = 0;
        return;
    }
    SecureZeroMemory(phCpuInformation,
                     sizeof(PerfSystemProcessorInfo) * static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors));
    NTSTATUS status = NtQuerySystemInformation(
        static_cast<SYSTEM_INFORMATION_CLASS>(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_PERF), phCpuInformation,
        static_cast<ULONG>(sizeof(PerfSystemProcessorInfo)) *
        static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors), NULL);
    if (!NtSuccess(status)) {
        sysCpuUsage = 0;
        return;
    }
    // Zero the CPU totals.
    SecureZeroMemory(&phCpuTotals, sizeof(PerfSystemProcessorInfo));
    for (ULONG i = 0; i < static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors); i++) {
        PerfSystemProcessorInfo *cpuInfo = &phCpuInformation[i];
        // KernelTime includes IdleTime.
        if (cpuInfo != nullptr) {
            cpuInfo->kernelTime.QuadPart -= cpuInfo->idleTime.QuadPart;
            phCpuTotals.dpcTime.QuadPart += cpuInfo->dpcTime.QuadPart;
            phCpuTotals.idleTime.QuadPart += cpuInfo->idleTime.QuadPart;
            phCpuTotals.interruptCount += cpuInfo->interruptCount;
            phCpuTotals.interruptTime.QuadPart += cpuInfo->interruptTime.QuadPart;
            phCpuTotals.kernelTime.QuadPart += cpuInfo->kernelTime.QuadPart;
            phCpuTotals.userTime.QuadPart += cpuInfo->userTime.QuadPart;
        }
    }
    PhUpdateDelta(phCpuKernelDelta, static_cast<ULONG64>(phCpuTotals.kernelTime.QuadPart));
    PhUpdateDelta(phCpuUserDelta, static_cast<ULONG64>(phCpuTotals.userTime.QuadPart));
    PhUpdateDelta(phCpuIdleDelta, static_cast<ULONG64>(phCpuTotals.idleTime.QuadPart));
    ULONG64 totalTime = phCpuKernelDelta.delta + phCpuUserDelta.delta + phCpuIdleDelta.delta;
    if (totalTime != 0) {
        phCpuKernelUsage = (FLOAT)phCpuKernelDelta.delta / totalTime;
        phCpuUserUsage = (FLOAT)phCpuUserDelta.delta / totalTime;
    } else {
        phCpuKernelUsage = INIT_VALUE;
        phCpuUserUsage = INIT_VALUE;
    }
    sysTotalTime = totalTime;
    sysCpuUsage = ((phCpuKernelUsage + phCpuUserUsage) * HUNDRED_CPU_USAGE);
}

void SysCpuCalc::DttPhpUpdateCpuInformation()
{
    if (dttPhCpuInformation == nullptr) {
        return;
    }
    ULONG processorNum = static_cast<ULONG>(phSystemBasicInformation.numberOfProcessors);
    SecureZeroMemory(dttPhCpuInformation, sizeof(PerfSystemProcessorInfo) * processorNum);
    NTSTATUS status = NtQuerySystemInformation(
        static_cast<SYSTEM_INFORMATION_CLASS>(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_PERF), dttPhCpuInformation,
        static_cast<ULONG>(sizeof(PerfSystemProcessorInfo)) * processorNum, NULL);
    if (!NtSuccess(status)) {
        return;
    }
    // Zero the CPU totals.
    SecureZeroMemory(&dttPhCpuTotals, sizeof(PerfSystemProcessorInfo));
    for (ULONG i = 0; i < processorNum; i++) {
        PerfSystemProcessorInfo *cpuInfo = &dttPhCpuInformation[i];
        // KernelTime includes IdleTime.
        if (cpuInfo != nullptr) {
            cpuInfo->kernelTime.QuadPart -= cpuInfo->idleTime.QuadPart;
            dttPhCpuTotals.dpcTime.QuadPart += cpuInfo->dpcTime.QuadPart;
            dttPhCpuTotals.idleTime.QuadPart += cpuInfo->idleTime.QuadPart;
            dttPhCpuTotals.interruptCount += cpuInfo->interruptCount;
            dttPhCpuTotals.interruptTime.QuadPart += cpuInfo->interruptTime.QuadPart;
            dttPhCpuTotals.kernelTime.QuadPart += cpuInfo->kernelTime.QuadPart;
            dttPhCpuTotals.userTime.QuadPart += cpuInfo->userTime.QuadPart;
        }
    }
    PhUpdateDelta(dttPhCpuKernelDelta, static_cast<ULONG64>(dttPhCpuTotals.kernelTime.QuadPart));
    PhUpdateDelta(dttPhCpuUserDelta, static_cast<ULONG64>(dttPhCpuTotals.userTime.QuadPart));
    PhUpdateDelta(dttPhCpuIdleDelta, static_cast<ULONG64>(dttPhCpuTotals.idleTime.QuadPart));
    dttSysTotalTime = dttPhCpuKernelDelta.delta + dttPhCpuUserDelta.delta + dttPhCpuIdleDelta.delta;
    LOG_INFO("dttSysTotalTime: {}", dttSysTotalTime);
}

std::unique_ptr<char[]> SysCpuCalc::GetProcessInfo()
{
    ULONG bufferSize = SYSTEM_PROCESSO_RPERFORMANCE_DISTRIBUTION;
    std::unique_ptr<char[]> systemProcessInfo = nullptr;
    DWORD len = 0;
    NTSTATUS status = 0;
    int loopIndex = 0;
    do {
        loopIndex++;
        try {
            systemProcessInfo = std::make_unique<char[]>(bufferSize);
        } catch (const std::bad_alloc& e) {
            LOG_ERR("system process info bad alloc.");
            return nullptr;
        }
        if (systemProcessInfo == nullptr) {
            return nullptr;
        }
        SecureZeroMemory(systemProcessInfo.get(), bufferSize);
        status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemProcessInformation),
                                          systemProcessInfo.get(), static_cast<ULONG>(bufferSize), &len);
        if (status == LENGTH_IS_NOT_MATCH) {
            systemProcessInfo = nullptr;
            bufferSize = (ENUM_SYSTEM_INFO_ADD_BUFF_SIZE + len);
        } else if (status) {
            systemProcessInfo = nullptr;
            return nullptr;
        }
    } while (status == LENGTH_IS_NOT_MATCH && loopIndex <= MAX_LOOP_TIMES);
    return std::move(systemProcessInfo);
}

// 清理掉已经关闭的进程
void SysCpuCalc::ClearExitProcess(const std::unordered_set<DWORD> &setProcssId,
                                  std::map<DWORD, SystemProcessItem> &mapProcInfo)
{
    auto procItr = mapProcInfo.begin();
    for (; procItr != mapProcInfo.end();) {
        if (setProcssId.find(procItr->first) == setProcssId.end()) {
            mapProcInfo.erase(procItr++);
            continue;
        }
        procItr++;
    }
}

void SysCpuCalc::UpdateProcInfo(SystemProcessItem &info, PerfSystemProcessInfo &proc, double timeDiff, bool isDttSample)
{
    PhUpdateDelta(info.cpuKernelDelta, static_cast<ULONG64>(proc.kernelTime.QuadPart));
    PhUpdateDelta(info.cpuUserDelta, static_cast<ULONG64>(proc.userTime.QuadPart));
    PhUpdateDelta(info.ioDelta, static_cast<ULONG64>(proc.readTransferCount.QuadPart + proc.writeTransferCount.QuadPart
        + proc.otherTransferCount.QuadPart));
    PhUpdateDelta(info.writeIoDelta, static_cast<ULONG64>(proc.writeTransferCount.QuadPart));
    PhUpdateDelta(info.readIoDelta, static_cast<ULONG64>(proc.readTransferCount.QuadPart));

    // io利用率(KB/s) = (本次io字节数 - 上次io字节数) / 经过的时间(s) / 1024
    info.diskReadPerSec = static_cast<ULONGLONG>(static_cast<double>(info.readIoDelta.delta) /
        DATA_CONVERSION_SIZE / timeDiff);
    info.diskWritePerSec = static_cast<ULONGLONG>(static_cast<double>(info.writeIoDelta.delta) /
        DATA_CONVERSION_SIZE / timeDiff);

    if (!isDttSample) {
        CalcIoTotal(info, timeDiff);
    }
    ULONG64 totalTime = isDttSample ? dttSysTotalTime : sysTotalTime;
    if (totalTime > 0) {
        info.cpuKernelUsage = static_cast<float>(info.cpuKernelDelta.delta) / totalTime;
        info.cpuUserUsage = static_cast<float>(info.cpuUserDelta.delta) / totalTime;
        info.cpuUsage = info.cpuKernelUsage + info.cpuUserUsage;
    }
    info.mem = proc.workingSetSize / DATA_CONVERSION_SIZE;
    info.vmem = proc.pagefileUsage / DATA_CONVERSION_SIZE;
}

void SysCpuCalc::InitProcInfo(SystemProcessItem &info, PerfSystemProcessInfo &proc, DWORD processId)
{
    info.processId = processId;
    std::wstring procName(proc.imageName.buffer, proc.imageName.length / sizeof(WCHAR));
    info.processName = StringProc::WStringToStringByUTF8(procName);
    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
    if (process != nullptr) {
        WCHAR processName[MAX_PATH] = { 0 };
        DWORD size = sizeof(processName) / sizeof(WCHAR) - 1;
        BOOL ret = QueryFullProcessImageNameW(process, 0, processName, &size);
        if (ret == TRUE) {
            std::wstring wProcessName(processName);
            std::string fullName = StringProc::WStringToStringByUTF8(wProcessName);
            info.fullProcessName = move(fullName);
        }
        CloseHandle(process);
    }
}

void SysCpuCalc::GetProcessMappingInfo(std::map<DWORD, SystemProcessItem> &mapProcInfo, bool isDttSample)
{
    std::unique_ptr<char[]> processInfo = GetProcessInfo();
    if (processInfo == nullptr) {
        return;
    }
    ULARGE_INTEGER interval = GetElapsedTime();
    // 时钟时间片长度,interval的单位是文件时间,以100ns为单位, 经过timeSlice转换为s
    double timeDiff = static_cast<double>(interval.QuadPart / TIME_SLICE);
    if (timeDiff <= 0) {
        LOG_ERR("ElapsedTimer is zero.");
        return;
    }
    PerfSystemProcessInfo *proc = reinterpret_cast<PerfSystemProcessInfo *>(processInfo.get());
    if (proc == nullptr) {
        return;
    }
    std::unordered_set<DWORD> setProcssId;
    for (uint32_t i = 0; i < MAX_PROCESS_SIZE && proc; i++) {
        if (proc->uniqueProcessId != nullptr) {
            ProcessProcInfo(*proc, setProcssId, mapProcInfo, timeDiff, isDttSample);
        }
        if (proc->nextEntryOffset == 0) {
            break;
        }
        proc = reinterpret_cast<PerfSystemProcessInfo *>(((PUCHAR)proc) + proc->nextEntryOffset);
    }
    // 清理掉已经关闭的进程
    ClearExitProcess(setProcssId, mapProcInfo);
}

void SysCpuCalc::ProcessProcInfo(PerfSystemProcessInfo &proc, std::unordered_set<DWORD> &setProcssId,
    std::map<DWORD, SystemProcessItem> &mapProcInfo, double timeDiff, bool isDttSample)
{
    DWORD processId = HandleToUlong(proc.uniqueProcessId);
    if (processId != 0 && processId != SYSTEM_ILD_PROCESS_ID) {
        setProcssId.emplace(processId);
        std::map<DWORD, SystemProcessItem>::iterator itr = mapProcInfo.find(processId);
        if (itr != mapProcInfo.end()) {
            UpdateProcInfo(itr->second, proc, timeDiff, isDttSample);
        } else {
            if (proc.imageName.buffer != nullptr && (proc.imageName.length / sizeof(WCHAR)) > 0) {
                SystemProcessItem processItem;
                InitProcInfo(processItem, proc, processId);
                UpdateProcInfo(processItem, proc, timeDiff, isDttSample);
                mapProcInfo.insert(std::pair<DWORD, SystemProcessItem>(processId, processItem));
            }
        }
    }
}

// 对于CPU太小的数据不做保存，避免存储了大量没有分析价值的数据
void SysCpuCalc::FilterEffectiveProcesses()
{
    std::unique_lock<std::mutex> lock(mapMtx);
    filterMapProcessInfo.clear();
    for (auto &proc : mapProcessInfo) {
        if (proc.second.cpuUsage >= MIN_CPU_USAGE || proc.second.ioToTal >= MINI_IO_TOTAL) {
            filterMapProcessInfo.emplace(proc);
            SystemProcessItem &info = proc.second;
        }
    }
}

// 计算6s内累计内存IO值
void SysCpuCalc::CalcIoTotal(SystemProcessItem &procInfo, double timeDiff)
{
    // 定时器轮询时长为2s，正常间隔时间2s多一点,大于3s则认为长时间未刷新
    const int intervalime = 2000;
    const int secToMs = 1000;
    if (timeDiff * secToMs > intervalime) {
        procInfo.ioToTal = 0;
        procInfo.ioTotalDeque.clear();
    } else {
        const int maxSaveDataSizeIo = 3;
        procInfo.ioToTal += procInfo.ioDelta.delta;
        procInfo.ioTotalDeque.push_back(procInfo.ioDelta.delta);
        if (procInfo.ioTotalDeque.size() > maxSaveDataSizeIo) {
            procInfo.ioToTal -= procInfo.ioTotalDeque.front();
            procInfo.ioTotalDeque.pop_front();
        }
    }
}

ULARGE_INTEGER SysCpuCalc::GetElapsedTime()
{
    FILETIME beginTime = { 0 };
    FILETIME endTime = { 0 };
    SystemTimeToFileTime(&lastTimePoint, &beginTime);
    GetLocalTime(&lastTimePoint);
    SystemTimeToFileTime(&lastTimePoint, &endTime);
    ULARGE_INTEGER const u1 = { beginTime.dwLowDateTime, beginTime.dwHighDateTime };
    ULARGE_INTEGER const u2 = { endTime.dwLowDateTime, endTime.dwHighDateTime };
    ULARGE_INTEGER interval = { 0 };
    interval.QuadPart = u2.QuadPart - u1.QuadPart;
    return interval;
}

void SysCpuCalc::CollectProcLoad()
{
    PhpUpdateCpuInformation();
    {
        std::unique_lock<std::mutex> lock(mapMtx);
        GetProcessMappingInfo(mapProcessInfo, false);
    }
    FilterEffectiveProcesses();
}

void SysCpuCalc::CollectProcCpuLoad()
{
    DttPhpUpdateCpuInformation();
    {
        std::unique_lock<std::mutex> lock(dttMapMtx);
        GetProcessMappingInfo(mapDttProcessInfo, true);
        std::map<DWORD, SysProcessCpuUsage> procCpuUsageMap = {};
        for (auto &proc : mapDttProcessInfo) {
            SystemProcessItem &info = proc.second;
            SysProcessCpuUsage proCpuInfo = {};
            proCpuInfo.processId = proc.second.processId;
            proCpuInfo.processName = proc.second.processName;
            proCpuInfo.cpuUsage = proc.second.cpuUsage;
            procCpuUsageMap.emplace(std::pair<DWORD, SysProcessCpuUsage>(proc.first, proCpuInfo));
        }
        LOG_INFO("procCpuUsageMap size: {}", procCpuUsageMap.size());
    }
    LOG_INFO("exit CollectProcCpuLoad");
}

float SysCpuCalc::GetSysCpuUsage()
{
    return sysCpuUsage;
}

bool SysCpuCalc::FilterAPPResourceActions()
{
    std::unordered_set<DWORD> appPidSet;
    GetProcessesPid(appWhiteList, appPidSet);
    if (appPidSet.size() == 0) {
        return false;
    }
    for (auto &proc : mapProcessInfo) {
        SystemProcessItem &info = proc.second;
        if (appPidSet.find(info.processId) != appPidSet.end()) {
            if (info.cpuUsage > compressFileMiniCpuUsage) {
                return true;
            }
        }
    }
    return false;
}

bool SysCpuCalc::FilterCompressDecompressActions()
{
    std::unordered_set<DWORD> compressingPidSet;
    GetProcessesPid(compressWhiteList, compressingPidSet);
    if (compressingPidSet.size() == 0) {
        return false;
    }
    for (auto &proc : mapProcessInfo) {
        SystemProcessItem &info = proc.second;
        if (compressingPidSet.find(info.processId) != compressingPidSet.end()) {
            if (info.processName.compare(SevenCompressName) == 0 && info.cpuUsage > compressFile7ZMiniCpuUsage &&
                info.diskReadPerSec == 0 && info.diskWritePerSec == 0) {
                LOG_INFO("Process name: {} Cpu usage: {}, disk read: {}, disk write: {}", info.processName,
                    info.cpuUsage, info.diskReadPerSec, info.diskWritePerSec);
                return true;
            }
            if (info.cpuUsage > compressFileMiniCpuUsage && info.diskReadPerSec > compressFileReadDisk &&
                info.diskWritePerSec > compressFileWriteDisk) {
                LOG_INFO("Process name: {} Cpu usage: {}, disk read: {}, disk write: {}", info.processName,
                    info.cpuUsage, info.diskReadPerSec, info.diskWritePerSec);
                return true;
            }
        }
    }
    return false;
}

bool SysCpuCalc::FilterFileCopyAndPasteActions()
{
    std::unordered_set<DWORD> pidSet;
    GetProcessesPid(copyPasteWhiteList, pidSet);
    if (pidSet.size() == 0) {
        return false;
    }
    for (auto &proc : mapProcessInfo) {
        SystemProcessItem &info = proc.second;
        if (pidSet.find(info.processId) != pidSet.end()) {
            if (info.diskReadPerSec >= fileReadDisk) {
                LOG_INFO("Process name: {} Cpu usage: {}, disk read: {}, disk write: {}", info.processName,
                    info.cpuUsage, info.diskReadPerSec, info.diskWritePerSec);
                return true;
            }
        }
    }
    return false;
}

void SysCpuCalc::GetProcessesPid(std::unordered_set<std::string> whiteList, std::unordered_set<DWORD> &pidList)
{
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == nullptr) {
        return;
    }
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    bool progress = Process32First(hProcessSnap, &pe);

    while (progress) {
        DWORD pid = pe.th32ProcessID;
        std::string inputFullName = GetFullNameByProcessId(pid);
        if (inputFullName.size() != 0) {
            std::string procName = GetProcNameFromPath(inputFullName);
            if (whiteList.find(procName) != whiteList.end() && pidList.find(pid) == pidList.end()) {
                std::cout << "Explore.exe pid: " << pid << std::endl;
                pidList.insert(pid);
            }
        }
        progress = Process32Next(hProcessSnap, &pe);
    }
    CloseHandle(hProcessSnap);
}

std::string SysCpuCalc::GetFullNameByProcessId(DWORD pid)
{
    std::string fullName = "";
    // 进程全路径
    WCHAR tempProcName[MAX_PATH] = { 0 };
    HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (processHandle != NULL) {
        GetModuleFileNameExW(processHandle, NULL, tempProcName, MAX_PATH);
        CloseHandle(processHandle);
        processHandle = NULL;
        std::wstring procName = tempProcName;
        fullName = WStringToString(procName);
    }
    return fullName;
}

std::string SysCpuCalc::GetProcNameFromPath(const std::string &fullPath)
{
    std::string::size_type index;
    std::string retStr = "";

    index = fullPath.rfind("\\");
    if (index != fullPath.npos) {
        retStr = fullPath.substr(index + 1);
    } else {
        retStr = fullPath;
    }
    return retStr;
}

std::string SysCpuCalc::WStringToString(const std::wstring &wString)
{
    std::string res = "";
    int len = WideCharToMultiByte(CP_ACP, 0, wString.c_str(), static_cast<int>(wString.size()), NULL, 0, NULL, NULL);
    if (len <= 0) {
        return res;
    }

    char *buffer = new char[len + 1];
    if (buffer == nullptr) {
        return res;
    }

    SecureZeroMemory(buffer, (len + 1) * sizeof(char));
    WideCharToMultiByte(CP_ACP, 0, wString.c_str(), static_cast<int>(wString.size()), buffer, len, NULL, NULL);
    buffer[len] = '\0';
    res.assign(buffer);
    delete[] buffer;

    return res;
}

bool SysCpuCalc::NtSuccess(const NTSTATUS status)
{
    return status >= 0;
}

void SysCpuCalc::PhUpdateDelta(PhUint64Delta &dltmgr, ULONG64 newValue)
{
    dltmgr.delta = newValue - dltmgr.value;
    dltmgr.value = newValue;
}

std::map<DWORD, SystemProcessItem> SysCpuCalc::GetProcessInfos()
{
    std::unique_lock<std::mutex> lock(mapMtx);
    return mapProcessInfo;
}

std::map<DWORD, SystemProcessItem> SysCpuCalc::GetFilterProcessInfos()
{
    std::unique_lock<std::mutex> lock(mapMtx);
    return filterMapProcessInfo;
}

double SysCpuCalc::GetCpuGhz()
{
    double retCpuGhz = 0.0;
    // 初始化COM库
    CoInitializeEx(0, COINIT_MULTITHREADED);
    CoInitializeSecurity(
        NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    // 获取WMI服务
    IWbemLocator* pLoc = NULL;
    IWbemServices* pSvc = NULL;

    HRESULT hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
    if (!SUCCEEDED(hres)) {
        return retCpuGhz;
    }
    hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
    if (!SUCCEEDED(hres)) {
        return retCpuGhz;
    }
    hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL,
        RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
    if (!SUCCEEDED(hres)) {
        return retCpuGhz;
    }
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_Processor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
    if (!SUCCEEDED(hres)) {
        return retCpuGhz;
    }
    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator) {
        hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
        if (uReturn == 0) {
            break;
        }
        VARIANT vtProp;
        // 获取CPU的当前频率
        hres = pclsObj->Get(L"CurrentClockSpeed", 0, &vtProp, 0, 0);
        if (SUCCEEDED(hres)) {
            retCpuGhz = vtProp.uintVal / THOUSAND_CPU_GHZ;
            VariantClear(&vtProp);
        }

        pclsObj->Release();
    }

    if (pEnumerator != NULL) {
        pEnumerator->Release();
        pEnumerator = NULL;
    }
    pSvc->Release();
    pLoc->Release();
    CoUninitialize();
    return retCpuGhz;
}